/***************************************************************************
 *
 *   Copyright (C) 2024 by Jesmigel Cantos
 *   Licensed under the Academic Free License version 2.1
 *
 ***************************************************************************/

#include "dsp/SKAParallelUnpacker.h"
#include "dsp/BitSeries.h"
#include "dsp/WeightedTimeSeries.h"

#include <gtest/gtest.h>

#ifdef HAVE_CUDA
#include <cuda_runtime.h>
#endif

#ifndef __dsp_ska1_SKAParallelUnpackerTest_h
#define __dsp_ska1_SKAParallelUnpackerTest_h

namespace dsp::test {

class SKAParallelUnpackerTest : public ::testing::TestWithParam<std::tuple<bool>>
{
  public:
    /**
     * @brief Construct a new SKAParallelUnpackerTest object
     */
    SKAParallelUnpackerTest();

    /**
     * @brief Destroy the SKAParallelUnpackerTest object
     */
    ~SKAParallelUnpackerTest() = default;

    /**
     * @brief Construct and configure the dsp::SKAParallelUnpacker object to be tested
     *
    */
    dsp::SKAParallelUnpacker* new_device_under_test();

    /**
     * @brief Generate test data for input to SKAParallelUnpacker
     *
     */
    void generate_data();

    /**
     * @brief Helper function for asserting output dsp::TimeSeries data
     *
     */
    void assert_output();

    /**
     * @brief Helper function setting the input and output containers used by the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void set_input_output(std::shared_ptr<dsp::SKAParallelUnpacker> spu);


    /**
     * @brief Helper function for calling the configure method of the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void call_configure(std::shared_ptr<dsp::SKAParallelUnpacker> spu);

    /**
     * @brief Helper function for calling the prepare method of the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void call_prepare(std::shared_ptr<dsp::SKAParallelUnpacker> spu);

    /**
     * @brief Helper function for calling the reserve method of the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void call_reserve(std::shared_ptr<dsp::SKAParallelUnpacker> spu);

    /**
     * @brief Helper function for calling the operate method of the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void call_operate(std::shared_ptr<dsp::SKAParallelUnpacker> spu);

    /**
     * @brief Helper function for calling the reset method of the SKAParallelUnpacker
     *
     * @param spu SKAParallelUnpacker shared pointer
     *
     */
     void call_reset(std::shared_ptr<dsp::SKAParallelUnpacker> spu);

    /**
     * @brief Helper function for loading the contents of a file into a string variable.
     *
     * @param file_name file name to be loaded
     *
     * @return std::string content of file selected
     *
     */
    std::string load_config_from_file(const std::string& file_name);

    //! input container
    Reference::To<dsp::ParallelBitSeries> input;

    //! output container
    Reference::To<dsp::TimeSeries> output;

    //! input to device container
    Reference::To<dsp::ParallelBitSeries> device_input;

    //! output of device container
    Reference::To<dsp::WeightedTimeSeries> device_output;

    //! device memory manager
    Reference::To<dsp::Memory> device_memory;

    //! observation configuration for data
    Reference::To<dsp::Observation> obs_data;

    //! observation configuration for weights
    Reference::To<dsp::Observation> obs_weights;

    const unsigned nbitseries{2};

    //! number of channels
    unsigned nchan{24};

    //! number of polarisations
    unsigned npol{2};

    //! number of dimensions
    unsigned ndim{2};

    //! number of time samples
    uint64_t ndat{32};

    //! number of bits
    uint64_t nbit{16};

    //! number of time samples per packet
    const uint32_t nsamp_per_packet = 32;

    //! number of frequency channels per packet
    const uint32_t nchan_per_packet = 24;

  protected:

    /**
     * @brief Sets up the test environment.
     *
     */
    void SetUp() override;

    /**
     * @brief Tears down the test environment.
     *
     */
    void TearDown() override;

    //! Set true when test should be performed on GPU
    bool on_gpu = false;

    //! Order of TimeSeries data
    dsp::TimeSeries::Order order = dsp::TimeSeries::OrderFPT;

    //! Helper function to determine the execution of gpu unit tests
    std::vector<bool> get_gpu_flags();

#ifdef HAVE_CUDA
    //! @brief CUDA stream handle.
    cudaStream_t stream{nullptr};
#endif
};

} // namespace dsp::test

#endif // __dsp_ska1_SKAParallelUnpackerTest_h
